package com.ruoyi.pay.service.impl;

import com.baomidou.mybatisplus.extension.api.R;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.finance.livestreaming.entity.SzOrder;
import com.ruoyi.finance.livestreaming.service.IFiDigitalLivestreamingService;
import com.ruoyi.pay.config.PayConfig;
import com.ruoyi.pay.entity.PayEntity;
import com.ruoyi.pay.service.ZFBPayService;
import com.ruoyi.pay.vo.PayVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author yqq
 * @date 2023/10/10
 * @Description
 */
@Service
public class ZFBPayServiceImpl implements ZFBPayService {

    private static final ConcurrentHashMap<String, PrivateKey> PRIVATE_KEYS = new ConcurrentHashMap<>();
    private static final String PRIVATE_KEY = "PRIVATE_KEY";
    @Autowired
    private PayConfig payConfig;

    @Autowired
    private IFiDigitalLivestreamingService iFiDigitalLivestreamingService;


    static {

        initPrivateKey("C:/payment_code/pay/wkst_SY.pfx", "wkst@2023");
        // initPrivateKey("/home/paizhibo/payment_code/pay/wkst_SY.pfx", "wkst@2023");
    }


    /**
     * 服务端统一下单参数
     * @param entity
     * @return
     */
    @Override
    public R<PayEntity> splicingParameter(PayVO entity, HttpServletRequest request) {
        // 创建订单
        SzOrder orderApp = iFiDigitalLivestreamingService.createOrderApp(entity);
        if (Objects.isNull(orderApp)){
            return R.failed("创建订单失败");
        }
        PayEntity payEntity = new PayEntity();
        entity.setCreate_ip("127_0_0_1");
        String clientIpAddress = getClientIpAddress(request);
        if (StringUtils.isNotEmpty(clientIpAddress)){
            entity.setCreate_ip(clientIpAddress);
        }
        entity.setVersion("10");
        entity.setMer_no(payConfig.getMid());
        entity.setAccsplit_flag("NO");
        entity.setSign_type("RSA");
        entity.setStore_id("000000");
        entity.setProduct_code("02020004");
        entity.setPay_extra("{\"wx_app_id\":\"wx123\",\"gh_ori_id\": \"gh_123\",\"path_url\":\"pages/zf/index?\",\"miniProgramType\":\"0\"}");
        entity.setJump_scheme("vcannft://scpay");
        entity.setMeta_option("[{\"sc\":\"wzsc://\",\"s\":\"Android\",\"id\":\"com.tencent.tmgp.sgame\",\"n\":\"测试\"},{\"sc\":\"wzsc://\",\"s\":\"Android\",\"id\":\"com.tencent.tmgp.sgame\",\"n\":\"测试\"}]");
        entity.setClear_cycle("3");

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        Calendar calendar = Calendar.getInstance();
        String createTime = sdf.format(calendar.getTime());
        calendar.add(Calendar.HOUR, 1);
        String endTime = sdf.format(calendar.getTime());
        entity.setExpire_time(endTime);
        entity.setCreate_time(createTime);
        //订单号
        entity.setMer_order_no(orderApp.getOrderId());
        entity.setReturn_url("");
        entity.setNotify_url("https://api.hfyinyi.cn/protal/notify/");
        BeanUtils.copyProperties(entity,payEntity);
        payEntity.setGoods_name(orderApp.getOrderName());
        Map<String, String> content = getContent(payEntity);
        String signContent = getSignContent(content);
        System.out.println("参与签名字符串：\n" + signContent);
        //商户私钥
        PrivateKey privateKey = getPrivateKey();
        String sign = sign(signContent, privateKey);
        System.out.println("签名串：\n" + sign);
        payEntity.setSign(sign);
        System.out.println("拼接完成：\n" + payEntity.toString());

        return R.ok(payEntity);
    }

    /**
     * 获取IP
     * @param request
     * @return
     */
    public String getClientIpAddress(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        //多个路由时，取第一个非unknown的ip
        if (StringUtils.isNotEmpty(ipAddress)){
            String[] split = ipAddress.split(",");
            for (String ip : split) {
                if ("unknown".equalsIgnoreCase(ip)){
                    ipAddress=ip;
                    break;
                }
            }
        }
        String newIpAddress=ipAddress.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ipAddress;
        return newIpAddress.replace(".","_");
    }

    public Map<String, String> getContent(PayEntity entity){

        Map<String, String> map = new LinkedHashMap<>();
        map.put("accsplit_flag", entity.getAccsplit_flag());
        map.put("create_ip", entity.getCreate_ip());
        map.put("create_time", entity.getCreate_time());

        map.put("mer_no", entity.getMer_no());
        map.put("mer_order_no", entity.getMer_order_no());
        map.put("notify_url", entity.getNotify_url());
        map.put("order_amt", entity.getOrder_amt());
        map.put("pay_extra",entity.getPay_extra());
        map.put("return_url", entity.getReturn_url());
        map.put("sign_type", entity.getSign_type());
        map.put("store_id", entity.getStore_id());
        map.put("version", entity.getVersion());
        return map;
    }

    public String getSignContent(Map<String, String> params) {
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (key != null && !key.isEmpty() && value != null && !value.isEmpty()) {
                content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
            }
        }
        return content.toString();
    }

    public String sign(String content, PrivateKey privateKey) {
        try {
            Signature signature = Signature.getInstance("SHA1WithRSA");
            signature.initSign(privateKey);
            signature.update(content.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public PrivateKey getPrivateKey() {
        return PRIVATE_KEYS.get(PRIVATE_KEY);
    }
    private static void initPrivateKey(String privateKeyPath, String password) {
        String classpathKey = "classpath:";
        InputStream inputStream = null;
        try {
            if (privateKeyPath.startsWith(classpathKey)) {
                inputStream = ZFBPayServiceImpl.class.getClassLoader().getResourceAsStream(privateKeyPath.substring(classpathKey.length()));
            } else {
                inputStream = Files.newInputStream(Paths.get(privateKeyPath));
            }

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            char[] pwdChar;
            if (password == null || password.trim().equals("")) {
                pwdChar = null;
            } else {
                pwdChar = password.toCharArray();
            }
            keyStore.load(inputStream, pwdChar);

            Enumeration<String> aliases = keyStore.aliases();
            String alias = null;
            if (aliases.hasMoreElements()) {
                alias = aliases.nextElement();
            }
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, pwdChar);
            PRIVATE_KEYS.put(PRIVATE_KEY, privateKey);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("私钥不存在");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("算法不存在");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ignored) {
                }
            }
        }
    }

}
